//#define GLFW_INCLUDE_VULKAN
//#include <GLFW/glfw3.h>
//
//#define GLM_FORCE_DEPTH_ZERO_TO_ONE
//#include <glm/vec4.hpp>
//#include <glm/mat4x4.hpp>
//
//#include <iostream>
//
//int main() {
//    glfwInit();
//
//    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
//    GLFWwindow* window = glfwCreateWindow(800, 600, "Vulkan window", nullptr, nullptr);
//
//    uint32_t extensionCount = 0;
//    vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
//
//    std::cout << extensionCount << " extensions supported\n";
//
//    glm::mat4 matrix;
//    glm::vec4 vec;
//    auto test = matrix * vec;
//
//    while (!glfwWindowShouldClose(window)) {
//        glfwPollEvents();
//    }
//
//    glfwDestroyWindow(window);
//
//    glfwTerminate();
//
//    return 0;
//}

#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>

#include <vulkan/vulkan.h>

#include <iostream>
#include <stdexcept>
#include <cstdlib>
#include <vector>
#include <cstring>
#include <RmlUi/Core.h>
#include <chrono>

const uint32_t WIDTH = 1200;
const uint32_t HEIGHT = 800;

const std::vector<const char*> validationLayers = {
	"VK_LAYER_KHRONOS_validation"
};


#ifdef NDEBUG
const bool enableValidationLayers = false;
#else
const bool enableValidationLayers = true;
#endif // NDEBUG


class HelloTraingleApplication {
public:
	void run() {
		initWindow();
		initVulkan();
		mainLoop();
		cleanup();
	}
private:
	GLFWwindow* wind;
	VkInstance instance;

	void initWindow() {
		glfwInit();
		glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
		glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
		wind = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);

	}
	void initVulkan() {
		createInstance();
	}
	void mainLoop() const {
		while (!glfwWindowShouldClose(wind)) {
			glfwPollEvents();
		}
	}
	void cleanup() const {
		vkDestroyInstance(instance, nullptr);
		glfwDestroyWindow(wind);
		glfwTerminate();
	}
	void createInstance() {

		if (enableValidationLayers && !checkValidationLayerSupport()) {
			throw std::runtime_error("validation layers requested, but not available");
		}


		VkApplicationInfo appInfo{};
		// Vulkan 中的许多结构体都要求您在sType成员中显式指定类型。
		// 这也是众多带有成员的结构体之一，pNext该成员将来可以指向扩展信息。
		// 我们在这里使用值初始化，将其保留为nullptr。
		appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
		appInfo.pApplicationName = "Hello triangle";
		appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
		appInfo.pEngineName = "No Engine";
		appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
		appInfo.apiVersion = VK_API_VERSION_1_4;


		// Vulkan 中的很多信息是通过结构体而不是函数参数传递的，
		// 因此我们需要再填充一个结构体来提供足够的信息来创建实例。
		// 下一个结构体是可选的，它告诉 Vulkan 驱动程序我们要使用哪些全局扩展和验证层。
		// 这里的全局是指它们适用于整个程序，而不是特定的设备，这将在接下来的几章中逐渐清晰。

		VkInstanceCreateInfo createInfo{};
		createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
		createInfo.pApplicationInfo = &appInfo;

		// 前两个参数很简单。接下来的两层指定所需的全局扩展。
		// 正如概述章节中提到的，Vulkan 是一个平台无关的 API，
		// 这意味着你需要一个扩展来与窗口系统交互。GLFW 有一个方便的内置函数，
		// 可以返回执行该操作所需的扩展，我们可以将这些扩展传递给结构体：
		uint32_t glfwExtensionCount = 0;
		const char** glfwExtensions;

		glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);

		createInfo.enabledExtensionCount = glfwExtensionCount;
		createInfo.ppEnabledExtensionNames = glfwExtensions;

		// 该结构体的最后两个成员决定了要启用的全局验证层。
		// 我们将在下一章中更深入地讨论这些内容，因此现在先将这些成员留空。
		// 如果启用了验证层
		if (enableValidationLayers) {
			createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
			createInfo.ppEnabledLayerNames = validationLayers.data();
		}
		// 没有启用验证层
		else {
			createInfo.enabledLayerCount = 0;
		}


		// 现在，我们已经指定了 Vulkan 创建实例所需的所有内容，
		// 最后可以发出vkCreateInstance调用：
		VkResult result = vkCreateInstance(&createInfo, nullptr, &instance);

		// 如果一切顺利，实例的句柄将存储在类成员中。几乎所有 Vulkan 函数
		// 都会返回一个或 错误代码VkInstance类型的值。要检查实例是否创建
		// 成功，我们无需存储结果，只需检查成功值即可：VkResultVK_SUCCESS
		if (result != VK_SUCCESS) {
			throw std::runtime_error("failed to create instance!");
		}

	}
	// 检查验证层支持
	bool checkValidationLayerSupport() {
		/*
		我们将添加一个新函数checkValidationLayerSupport来检查所有请求的层是否可用。
		首先，使用该vkEnumerateInstanceLayerProperties函数列出所有可用的层。
		其用法与实例创建章节中讨论的相同。接下来，检查列表中
		vkEnumerateInstanceExtensionProperties是否存在所有层。
		您可能需要包含for validationLayersavailableLayers<cstring>strcmp
		*/
		uint32_t layerCount;
		vkEnumerateInstanceLayerProperties(&layerCount, nullptr);

		std::vector<VkLayerProperties> availableLayers(layerCount);
		vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());

		for (const char* layerName : validationLayers) {
			bool layerFound = false;

			for (const auto& layerProperties : availableLayers) {
				if (strcmp(layerName, layerProperties.layerName) == 0) {
					layerFound = true;
					break;
				}

			}
			if (!layerFound) {
				return false;
			}
		}
		return true;
	}
};


class RmlUiDemo : public Rml::SystemInterface {
public:
	// 构造函数：
	RmlUiDemo() {
		// 初始化计时器
		// 记录程序/对象初始化的起始时间点
		// std::chrono::high_resolution_clock：当前系统最高精度的时钟（通常是纳秒级精度）。
		// now()：获取时钟的当前时间点。
		// 结果存入 start_time（一个time_point类型的变量），作为后续计算时间间隔的基准点。
		start_time = std::chrono::high_resolution_clock::now();
	}

	// 计算从 start_time 到当前时刻经过的时间（秒）。
	virtual double GetElapsedTime() override {
		// 获取当前时间：
		auto current_time = std::chrono::high_resolution_clock::now();
		// 计算时间间隔：
		// current_time - start_time：得到两个时间点之间的时间差（类型为 duration）。
		// duration_cast<std::chrono::microseconds>：将时间差转换为微秒（1微秒 = 10⁻⁶秒）为单位，确保精度。
		auto dutation = std::chrono::duration_cast<std::chrono::microseconds>(current_time - start_time);
		// duration.count()：获取微秒数的整数值。
		// 除以 1000000.0 将微秒转换为秒（例如 500000μs → 0.5s）。
		return dutation.count() / 1000000.0;
	}
private:
	// 定义一个用于存储开始时间点的变量。
	// td::chrono::time_point：表示某个时钟上的特定时间点。
	// <std::chrono::high_resolution_clock>：指明该时间点基于高精度时钟。
	std::chrono::time_point<std::chrono::high_resolution_clock> start_time;

};



int main() {
	HelloTraingleApplication app;
	try {
		app.run();
	}
	catch (const std::exception& e) {
		std::cerr << e.what() << std::endl;
		return EXIT_FAILURE;

	}
	return EXIT_SUCCESS;
}